package com.fl.niu.common.util;

import io.minio.MinioClient;
import io.minio.errors.InvalidEndpointException;
import io.minio.errors.InvalidPortException;
import io.minio.policy.PolicyType;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import javax.imageio.ImageIO;
import java.io.*;
import java.time.LocalDate;
import java.util.Random;

//import org.springframework.mock.web.MockMultipartFile;
//import org.apache.commons.fileupload.FileItemFactory;


/**
 * 对象存储工具类
 *
 * @author 10552
 */
public class MinioUtil {
    private static final Logger log = LoggerFactory.getLogger(MinioUtil.class);
    //Mino服务器的AccessKey
    private final transient static String ACCESS_KEY = "admin";
    //Mino服务器的SecretKey
    private final transient static String SECRET_KEY = "12345zzz";
    //桶名称
    private final transient static String BUCKET_NAME = "niucloud";
    //读写分离-上传服务器
    private final transient static String OSS_MINIO_URL_WRITE = "https://api.jsflems.com";
    //读写分离-下载服务器
    private final transient static String OSS_MINIO_URL_READ = "https://api.jsflems.com";
    //minio服务端口，默认是9000
    private final transient static int OSS_MINIO_PORT = 3202;
    private transient static boolean BUCKET_EXISTS = false;

    //单例模式-内部类实现
    private static class MinioClientHolder {
        private static MinioClient minioClient;

        static {
            try {
                minioClient = new MinioClient(OSS_MINIO_URL_WRITE, OSS_MINIO_PORT, ACCESS_KEY, SECRET_KEY);
            } catch (InvalidEndpointException e) {
                e.printStackTrace();
            } catch (InvalidPortException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 获取minio客户端实例
     *
     * @return
     */
    public static MinioClient getMinioClient() {
        return MinioClientHolder.minioClient;
    }

    /**
     * 上传文件
     * 支持单文件，多文件
     * 返回文件访问路径，多文件以分号‘；’分隔
     *
     * @param muFiles
     * @return
     */
    public static String uploadFiles(MultipartFile... muFiles) {
        if (muFiles.length < 1) {
            throw new RuntimeException("上传文件为空！");
        }
        StringBuilder str = new StringBuilder();
        for (MultipartFile muFile : muFiles) {
            str.append(uploadFile(muFile));
            str.append(";");
        }
        return str.deleteCharAt(str.length() - 1).toString();

    }

    /**
     * 内部方法
     * 上传文件
     *
     * @param muFile
     * @return
     */
    private static String uploadFile(MultipartFile muFile) {
        String fileName = getFilePathName(muFile, false);
        String viewUrl = "";
        String imgUrl = "";
        try {
            MinioClient minioClient = getMinioClient();
            if (!BUCKET_EXISTS && !minioClient.bucketExists(BUCKET_NAME)) {
                minioClient.makeBucket(BUCKET_NAME);
                minioClient.setBucketPolicy(BUCKET_NAME, "", PolicyType.READ_ONLY);
                BUCKET_EXISTS = true;
            }
            InputStream inputStream = muFile.getInputStream();
            //如果是图片文件就进行压缩
            if (ImageUtil.isImage(muFile.getOriginalFilename())) {
                inputStream = ImageUtil.getInputStream(
                        ImageUtil.setWatermark(
                                ImageUtil.compress(
                                        ImageIO.read(inputStream))),
                        ImageUtil.getFileExtention(muFile.getOriginalFilename()));
            }
            File file = null;
            //如果是视频文件就进行压缩

            if(ImageUtil.isVideo(muFile.getOriginalFilename())){
                file = multipartFileToFile(muFile);

                VideoUtil.ReadVideoSize(file);
                file = VideoUtil.compressionVideo(file,fileName);
                VideoUtil.ReadVideoSize(file);
                inputStream = new FileInputStream(file);
                File file1 =VideoUtil.getVideoPic(file,"video.jpg");
                if(file1 != null){
                    imgUrl = uploadCoverImg(file1);
                }
                delteTempFile(file);
            }


            minioClient.putObject(BUCKET_NAME, fileName, inputStream, muFile.getContentType());
//            viewUrl = getMinioClient().presignedGetObject(BUCKET_NAME, fileName, 10000);
            viewUrl = OSS_MINIO_URL_READ + ":" + OSS_MINIO_PORT + "/" + BUCKET_NAME + fileName;
        } catch (Exception e) {
            log.error("文件上传失败", e);
            throw new RuntimeException("文件上传失败");
        }


//        return OSS_MINIO_URL_READ + BUCKET_NAME + fileName;
        if(imgUrl != ""){
            return viewUrl +","+imgUrl;
        }else{
            return viewUrl;
        }
    }

    private static String uploadCoverImg(File muFile) throws IOException {
        MultipartFile multipartFile = new CommonsMultipartFile(createFileItem(muFile,muFile.getName()));
        String fileName = getFilePathName(multipartFile, false);
        String viewUrl = "";
        try {
            MinioClient minioClient = getMinioClient();
            if (!BUCKET_EXISTS && !minioClient.bucketExists(BUCKET_NAME)) {
                minioClient.makeBucket(BUCKET_NAME);
                minioClient.setBucketPolicy(BUCKET_NAME, "", PolicyType.READ_ONLY);
                BUCKET_EXISTS = true;
            }
            InputStream inputStream1 = multipartFile.getInputStream();
            //如果是图片文件就进行压缩

            minioClient.putObject(BUCKET_NAME, fileName, inputStream1, multipartFile.getContentType());
//            viewUrl = getMinioClient().presignedGetObject(BUCKET_NAME, fileName, 10000);
            viewUrl = OSS_MINIO_URL_READ + ":" + OSS_MINIO_PORT + "/" + BUCKET_NAME + fileName;
        } catch (Exception e) {
            log.error("文件上传失败", e);
            throw new RuntimeException("文件上传失败");
        }
        return viewUrl;
    }

    /**
     * MultipartFile 转 File
     *
     * @param file
     * @throws Exception
     */
    public static File multipartFileToFile(MultipartFile file) throws Exception {

        File toFile = null;
        if (file.equals("") || file.getSize() <= 0) {
            file = null;
        } else {
            InputStream ins = null;
            ins = file.getInputStream();
            toFile = new File(file.getOriginalFilename());
            inputStreamToFile(ins, toFile);
            ins.close();
        }
        return toFile;
    }

    //获取流文件
    private static void inputStreamToFile(InputStream ins, File file) {
        try {
            OutputStream os = new FileOutputStream(file);
            int bytesRead = 0;
            byte[] buffer = new byte[8192];
            while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            os.close();
            ins.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 删除本地临时文件
     * @param file
     */
    public static void delteTempFile(File file) {
        if (file != null) {
            File del = new File(file.toURI());
            del.delete();
        }
    }

    private static FileItem createFileItem(File file, String fieldName) {
        FileItemFactory factory = new DiskFileItemFactory(16, null);
        FileItem item = factory.createItem(fieldName, "text/plain", true, file.getName());
        int bytesRead = 0;
        byte[] buffer = new byte[8192];
        try {
            FileInputStream fis = new FileInputStream(file);
            OutputStream os = item.getOutputStream();
            while ((bytesRead = fis.read(buffer, 0, 8192)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            os.close();
            fis.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return item;
    }
    /**
     * MultipartFile 转 File
     */
//    public void inputStreamToFile(InputStream ins, File file) {
//        try {
//            OutputStream os = new FileOutputStream(file);
//            int bytesRead = 0;
//            byte[] buffer = new byte[8192];
//            while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
//                os.write(buffer, 0, bytesRead);
//            }
//            os.close();
//            ins.close();
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//    }

    /**
     * MultipartFile 转 File 获取文件名称
     */
//    public String getFileName(MultipartFile file) throws IOException {
//        File toFile = null;
//        if (file.equals("") || file.getSize() <= 0) {
//            file = null;
//        } else {
//            InputStream ins = null;
//            ins = file.getInputStream();
//            toFile = new File(file.getOriginalFilename());
//            inputStreamToFile(ins, toFile);
//            ins.close();
//        }
//        return String.valueOf(toFile);
//    }


    /**
     * 压缩视频
     */
//    public void zipVideo(MultipartFile file, String proFileName, String suffixName) throws IOException {
//        String fileName = getFileName(file);
//        File source = new File(fileName);
//        File target = new File(proFileName + "." + suffixName);
//        try {
//            // 音频编码设置
//            AudioAttributes audio = new AudioAttributes();
//            audio.setCodec("libmp3lame");
//            audio.setBitRate(new Integer(64000));
//            audio.setChannels(new Integer(1));
//            audio.setSamplingRate(new Integer(22050));
//
//            // 视频编码设置
//            VideoAttributes video = new VideoAttributes();
//            video.setCodec("mpeg4");
//            video.setBitRate(new Integer(160000));
//            video.setFrameRate(new Integer(15));
//            //            video.setSize(new VideoSize(100, 150));
//
//            // 视频转码编码设置
//            EncodingAttributes attrs = new EncodingAttributes();
//            attrs.setFormat(suffixName);
//            attrs.setAudioAttributes(audio);
//            attrs.setVideoAttributes(video);
//
//            // 编码器
//            Encoder encoder = new Encoder();
//            encoder.encode(source, target, attrs);
//        } catch (EncoderException e) {
//            e.printStackTrace();
//        }
//    }

    /**
     * 压缩视频
     * 功能描述:
     * @Author xiyou
     * @Description
     * @Date 20:29 2019/4/15
     * @Param
     * @return
     **/
//    public void convetors(MultipartFile file, String proFileName, String suffixName)
//            throws Exception {
//        String fileName = getFileName(file);
//        File source = new File(fileName);
//        File target = new File(proFileName + "." + suffixName);
//        List<String> command = new ArrayList<String>();
//        command.add(ffmpegEXE);
//        command.add("-i");
//        command.add(String.valueOf(source));
//        command.add("-b:v");
//        command.add("400k");
//        command.add("-s");
//        command.add("544x960");
//        command.add(String.valueOf(target));
//        System.out.println("命令：" + command);
//        ProcessBuilder builder = new ProcessBuilder(command);
//        Process process = null;
//        try {
//            process = builder.start();
//        } catch (IOException e) {
//            // TODO Auto-generated catch block
//            e.printStackTrace();
//        }
//        // 使用这种方式会在瞬间大量消耗CPU和内存等系统资源，所以这里我们需要对流进行处理
//        InputStream errorStream = process.getErrorStream();
//        InputStreamReader inputStreamReader = new InputStreamReader(errorStream);
//        BufferedReader br = new BufferedReader(inputStreamReader);
//
//        String line = "";
//        while ((line = br.readLine()) != null) {
//        }
//        if (br != null) {
//            br.close();
//        }
//        if (inputStreamReader != null) {
//            inputStreamReader.close();
//        }
//        if (errorStream != null) {
//            errorStream.close();
//        }
//
//    }
    /**
     * 获取文件名
     *
     * @param muFile   文件
     * @param isRetain 是否保留源文件名
     * @return 返回文件名，以当前年月日作为前缀路径
     */
    public static String getFilePathName(MultipartFile muFile, boolean isRetain) {
        String fileName = muFile.getOriginalFilename();
        String name = fileName;
        String prefix = "";
        if (fileName.indexOf('.') != -1) {
            name = fileName.substring(0, fileName.indexOf('.'));
            prefix = fileName.substring(fileName.lastIndexOf("."));
        }

        LocalDate date = LocalDate.now();
        StringBuilder filePathName = new StringBuilder("/upload/");
        filePathName.append(date.getYear());
        filePathName.append("/");
        filePathName.append(date.getMonthValue());
        filePathName.append("/");
        filePathName.append(date.getDayOfMonth());
        filePathName.append("/");
        //添加随机后缀
        Random r = new Random();
        int pix = r.ints(1, (100 + 1)).findFirst().getAsInt();
        filePathName.append(System.currentTimeMillis());
        filePathName.append("" + pix);
        //文件名超过32字符则截取
        if (isRetain) {
            filePathName.append("_");
            if (name.length() >= 32) {
                name = name.substring(0, 32);
            }
            filePathName.append(name);
        }
        filePathName.append(prefix);
        return filePathName.toString();
    }
}
